

 /*
 This file 'droppable' is part of Firebird Integrated Solution 1.0

 Copyright (c) 2015 Lincong

 Contact:  
        Email: lincong1987@gmail.com

        QQ: 159257119
 
 See Usage at http://www.jplatformx.com/firebird

 Create date: 2015-07-14 04:37
 */


 (function ($, undefined) {

     $.widget("ui.droppable", {
         version: "1.9.2",
         widgetEventPrefix: "drop",
         options: {
             accept: '*',
             activeClass: false,
             addClasses: true,
             greedy: false,
             hoverClass: false,
             scope: 'default',
             tolerance: 'intersect'
         },
         _create: function () {

             var o = this.options, accept = o.accept;
             this.isover = 0;
             this.isout = 1;

             this.accept = $.isFunction(accept) ? accept : function (d) {
                 return d.is(accept);
             };

             //Store the droppable's proportions
             this.proportions = {width: this.element[0].offsetWidth, height: this.element[0].offsetHeight};

             // Add the reference and positions to the manager
             $.ui.ddmanager.droppables[o.scope] = $.ui.ddmanager.droppables[o.scope] || [];
             $.ui.ddmanager.droppables[o.scope].push(this);

             (o.addClasses && this.element.addClass("ui-droppable"));

         },

         _destroy: function () {
             var drop = $.ui.ddmanager.droppables[this.options.scope];
             for (var i = 0; i < drop.length; i++)
                 if (drop[i] == this)
                     drop.splice(i, 1);

             this.element.removeClass("ui-droppable ui-droppable-disabled");
         },

         _setOption: function (key, value) {

             if (key == 'accept') {
                 this.accept = $.isFunction(value) ? value : function (d) {
                     return d.is(value);
                 };
             }
             $.Widget.prototype._setOption.apply(this, arguments);
         },

         _activate: function (event) {
             var draggable = $.ui.ddmanager.current;
             if (this.options.activeClass) this.element.addClass(this.options.activeClass);
             (draggable && this._trigger('activate', event, this.ui(draggable)));
         },

         _deactivate: function (event) {
             var draggable = $.ui.ddmanager.current;
             if (this.options.activeClass) this.element.removeClass(this.options.activeClass);
             (draggable && this._trigger('deactivate', event, this.ui(draggable)));
         },

         _over: function (event) {

             var draggable = $.ui.ddmanager.current;
             if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element

             if (this.accept.call(this.element[0], (draggable.currentItem || draggable.element))) {
                 if (this.options.hoverClass) this.element.addClass(this.options.hoverClass);
                 this._trigger('over', event, this.ui(draggable));
             }

         },

         _out: function (event) {

             var draggable = $.ui.ddmanager.current;
             if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element

             if (this.accept.call(this.element[0], (draggable.currentItem || draggable.element))) {
                 if (this.options.hoverClass) this.element.removeClass(this.options.hoverClass);
                 this._trigger('out', event, this.ui(draggable));
             }

         },

         _drop: function (event, custom) {

             var draggable = custom || $.ui.ddmanager.current;
             if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return false; // Bail if draggable and droppable are same element

             var childrenIntersection = false;
             this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function () {
                 var inst = $.data(this, 'droppable');
                 if (
                     inst.options.greedy
                     && !inst.options.disabled
                     && inst.options.scope == draggable.options.scope
                     && inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element))
                     && $.ui.intersect(draggable, $.extend(inst, {offset: inst.element.offset()}), inst.options.tolerance)
                 ) {
                     childrenIntersection = true;
                     return false;
                 }
             });
             if (childrenIntersection) return false;

             if (this.accept.call(this.element[0], (draggable.currentItem || draggable.element))) {
                 if (this.options.activeClass) this.element.removeClass(this.options.activeClass);
                 if (this.options.hoverClass) this.element.removeClass(this.options.hoverClass);
                 this._trigger('drop', event, this.ui(draggable));
                 return this.element;
             }

             return false;

         },

         ui: function (c) {
             return {
                 draggable: (c.currentItem || c.element),
                 helper: c.helper,
                 position: c.position,
                 offset: c.positionAbs
             };
         }

     });

     $.ui.intersect = function (draggable, droppable, toleranceMode) {

         if (!droppable.offset) return false;

         var x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width,
             y1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height;
         var l = droppable.offset.left, r = l + droppable.proportions.width,
             t = droppable.offset.top, b = t + droppable.proportions.height;

         switch (toleranceMode) {
             case 'fit':
                 return (l <= x1 && x2 <= r
                 && t <= y1 && y2 <= b);
                 break;
             case 'intersect':
                 return (l < x1 + (draggable.helperProportions.width / 2) // Right Half
                 && x2 - (draggable.helperProportions.width / 2) < r // Left Half
                 && t < y1 + (draggable.helperProportions.height / 2) // Bottom Half
                 && y2 - (draggable.helperProportions.height / 2) < b ); // Top Half
                 break;
             case 'pointer':
                 var draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left),
                     draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top),
                     isOver = $.ui.isOver(draggableTop, draggableLeft, t, l, droppable.proportions.height, droppable.proportions.width);
                 return isOver;
                 break;
             case 'touch':
                 return (
                         (y1 >= t && y1 <= b) ||	// Top edge touching
                         (y2 >= t && y2 <= b) ||	// Bottom edge touching
                         (y1 < t && y2 > b)		// Surrounded vertically
                     ) && (
                         (x1 >= l && x1 <= r) ||	// Left edge touching
                         (x2 >= l && x2 <= r) ||	// Right edge touching
                         (x1 < l && x2 > r)		// Surrounded horizontally
                     );
                 break;
             default:
                 return false;
                 break;
         }

     };

     /*
      This manager tracks offsets of draggables and droppables
      */
     $.ui.ddmanager = {
         current: null,
         droppables: {'default': []},
         prepareOffsets: function (t, event) {

             var m = $.ui.ddmanager.droppables[t.options.scope] || [];
             var type = event ? event.type : null; // workaround for #2317
             var list = (t.currentItem || t.element).find(":data(droppable)").andSelf();

             droppablesLoop: for (var i = 0; i < m.length; i++) {

                 if (m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0], (t.currentItem || t.element)))) continue;	//No disabled and non-accepted
                 for (var j = 0; j < list.length; j++) {
                     if (list[j] == m[i].element[0]) {
                         m[i].proportions.height = 0;
                         continue droppablesLoop;
                     }
                 }
                 ; //Filter out elements in the current dragged item
                 m[i].visible = m[i].element.css("display") != "none";
                 if (!m[i].visible) continue; 									//If the element is not visible, continue

                 if (type == "mousedown") m[i]._activate.call(m[i], event); //Activate the droppable if used directly from draggables

                 m[i].offset = m[i].element.offset();
                 m[i].proportions = {width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight};

             }

         },
         drop: function (draggable, event) {

             var dropped = false;
             $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function () {

                 if (!this.options) return;
                 if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance))
                     dropped = this._drop.call(this, event) || dropped;

                 if (!this.options.disabled && this.visible && this.accept.call(this.element[0], (draggable.currentItem || draggable.element))) {
                     this.isout = 1;
                     this.isover = 0;
                     this._deactivate.call(this, event);
                 }

             });
             return dropped;

         },
         dragStart: function (draggable, event) {
             //Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003)
             draggable.element.parentsUntil("body").bind("scroll.droppable", function () {
                 if (!draggable.options.refreshPositions) $.ui.ddmanager.prepareOffsets(draggable, event);
             });
         },
         drag: function (draggable, event) {

             //If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse.
             if (draggable.options.refreshPositions) $.ui.ddmanager.prepareOffsets(draggable, event);

             //Run through all droppables and check their positions based on specific tolerance options
             $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function () {

                 if (this.options.disabled || this.greedyChild || !this.visible) return;
                 var intersects = $.ui.intersect(draggable, this, this.options.tolerance);

                 var c = !intersects && this.isover == 1 ? 'isout' : (intersects && this.isover == 0 ? 'isover' : null);
                 if (!c) return;

                 var parentInstance;
                 if (this.options.greedy) {
                     // find droppable parents with same scope
                     var scope = this.options.scope;
                     var parent = this.element.parents(':data(droppable)').filter(function () {
                         return $.data(this, 'droppable').options.scope === scope;
                     });

                     if (parent.length) {
                         parentInstance = $.data(parent[0], 'droppable');
                         parentInstance.greedyChild = (c == 'isover' ? 1 : 0);
                     }
                 }

                 // we just moved into a greedy child
                 if (parentInstance && c == 'isover') {
                     parentInstance['isover'] = 0;
                     parentInstance['isout'] = 1;
                     parentInstance._out.call(parentInstance, event);
                 }

                 this[c] = 1;
                 this[c == 'isout' ? 'isover' : 'isout'] = 0;
                 this[c == "isover" ? "_over" : "_out"].call(this, event);

                 // we just moved out of a greedy child
                 if (parentInstance && c == 'isout') {
                     parentInstance['isout'] = 0;
                     parentInstance['isover'] = 1;
                     parentInstance._over.call(parentInstance, event);
                 }
             });

         },
         dragStop: function (draggable, event) {
             draggable.element.parentsUntil("body").unbind("scroll.droppable");
             //Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003)
             if (!draggable.options.refreshPositions) $.ui.ddmanager.prepareOffsets(draggable, event);
         }
     };

 })(jQuery);